package com.summer.bilibili.model;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.TypeUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.summer.bilibili.util.PageImpl;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.springframework.lang.Nullable;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 通用搜索实体
 */
@Data
@Deprecated
// 关联的试题类型，用于类型安全的字段引用
public class BaseSearch< T > implements Serializable {
    /**
     * 作为查询条件的Map
     * 值为null的会被转为 is null
     */
    @Null // 校验要求该字段必须为null
    @Deprecated
    // SFunction<T, ?>：MyBatis-Plus 的列函数式引用（如 User::getName）
    // Object：查询值（支持 null 值转 IS NULL）
    private Map < SFunction < T, ? >, Object > allEqMap;
    /**
     * 查询一组id
     */
    @Deprecated
    private List < Long > ids;
    /**
     * 分页
     */
    @NotNull
    @Min(value = 1)
    private int pageNum = 1;
    /**
     * 每页条数 (禁止同时使用pageSize和selectCollection)
     * 有时会让pageSize为0，目的是查total
     */
    @NotNull
    @Min(value = 0)
    private int pageSize = 10;
    /**
     * 是否先查找总数,否则page的total属性为null
     */
    @NotNull
    private boolean searchCount = true;
    /**
     * 默认降序查找
     */
    @NotNull
    private boolean asc = false;
    /**
     * 搜索关键字
     */
    @Length(max = 64, message = "搜索关键字不能超过64个字符")
    private String keyword;

    /**
     * 分页对象创建
     *
     * @param <R>
     * @return PageImpl < R >  自定义分页对象
     */
    public < R > PageImpl < R > createPage () {
        return new PageImpl <> ( pageNum , pageSize , searchCount );
    }

    /**
     * 条件创建构造方法，动态添加等值查询条件
     *
     * @param col
     * @param value
     * @param <R>
     */
    public < R > void addEq ( SFunction < T, R > col , R value ) {
        if ( this.allEqMap == null ) {
            this.allEqMap = new LinkedHashMap <> ( );
        }
        this.allEqMap.put ( col , value );
    }

    /**
     * 获取泛型T的class,必须继承该类后使用
     */
    @SuppressWarnings("all") // 压制泛型类型转换的未检警告
    private Class < T > getEntityClass () {
        return (Class < T >) TypeUtil.getTypeArgument ( getClass ( ) ); // 获取泛型参数
    }

    /**
     * 分页查询执行
     *
     * @param wrapper
     * @param resultType
     * @param <R>
     * @return
     */
    @Deprecated
    public < R > PageImpl < R > page ( MPJLambdaWrapper < T > wrapper , @Nullable Class < R > resultType ) {
        // 确定返回类型
        if ( resultType == null ) {
            resultType = (Class < R >) wrapper.getEntityClass ( );
        }
        // 创建分页对象
        PageImpl < R > page = createPage ( );
        wrapper.selectAll ( wrapper.getEntityClass ( ) )
                .distinct ( ) //将所有select字段组合起来去重
                .allEq ( Objects.nonNull ( this.getAllEqMap ( ) ) , this.getAllEqMap ( ) , true )
                .page ( page , resultType ); // 调用 MPJ 的 page()执行物理分页查询
        return page;
    }

    /**
     * 查询包装器的快捷入口
     *
     * @return 查询构造器 wrapper
     */
    @Deprecated
    public MPJLambdaWrapper < T > wrapper () {
        return wrapper ( getEntityClass ( ) , "t" );
    }

    /**
     * 查询构造器
     *
     * @param modelClass
     * @param alias
     * @param <R>
     * @return
     */
    @Deprecated
    public < R > MPJLambdaWrapper < R > wrapper ( Class < R > modelClass , String alias ) {
        return new MPJLambdaWrapper <> ( modelClass , alias )
                .selectAll ( modelClass ) // 选择所有字段
                .distinct ( ) // 去重
                .in ( CollUtil.isNotEmpty ( ids ) , "id" , ids ) // ID批量查询
                .allEq ( Objects.nonNull ( this.getAllEqMap ( ) ) , this.getAllEqMap ( ) , true );
    }

    /**
     * 单挑查询优化
     *
     * @param column
     * @param value
     * @param <R>
     * @param <S>
     * @return
     */
    @Deprecated
    public < R, S extends BaseSearch < T > > S one ( SFunction < T, R > column , R value ) {
        this.setPageNum ( 1 );
        this.setPageSize ( 1 );
        this.setSearchCount ( false ); // 跳过count查询
        this.addEq ( column , value ); // 添加等值条件保证精度
        return (S) this;
    }
}
